/**
*
* @file
*		heap_test_ludmila
*
* @brief
*		Tests for heap by ludmila@
*/

#include <Windows.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "../../api/heap.h"
#include "../../src/ludmila/heap_ludmila.h"
#include "../../src/Julia/heap_julia.h"
#include "../../src/dm_karpov/heap_dmk.h"
#include "../../src/gauss/heap_gauss.h"

#define NO_MEMORY_ERROR_CODE 1

//#define PRIVATE_DEBUG

#ifdef PRIVATE_DEBUG 
#define heap876 heap_ludmila
#endif

const int num_tags = 10;
const int t_num = 10;

/**
 * abstract test
 */

int t_test( heap876* hp )
{
	printf("heap<%s> volume is %p ", hp->get_name(), hp->get_volume() );
	return 0;
}

/**
 * general test
 */

int test_general( void* heap )
{
	heap876* hp = (heap876*)heap;
	unsigned long long steps = 1000;
	clock_t start;
	start  = clock();
	printf("heap<%s> volume is %p ", hp->get_name(), hp->get_volume() );
	std::map<void*, int> ptr_map;
	map<void*, int>::iterator iter;
	for (unsigned int step = 0; step < steps; step++)
	{
		int action = rand();
		unsigned int tag = rand() % num_tags;
		int pid = GetCurrentThreadId();
		printf("%d ", pid);
		if (action % 2 == 0)
		{
			float rand_percent = ((float)(rand() % 100)) / 100;
			size_t sz = (size_t)((int)((rand_percent * (hp->get_volume() / (128 * 100)) + 1)) * 128 + rand() % 128);
			printf("Alloc action size %d tag %d\n", sz, tag);
			void* ptr = hp->alloc(sz, tag);
			if (ptr)
			{
				ptr_map.insert(std::make_pair(ptr, tag));
				memset(ptr, 0x01010101, sz);
			}
		}
		if ((action % 3 == 0 || action % 5) && action % 2 != 0)
		{
			if (ptr_map.empty() == 0 )
			{
				printf("Free action\n");
				iter = ptr_map.begin();
				int rand_piece = rand() % (ptr_map.size());
				for (int i = 1; i < rand_piece - 1; i++)
				{
					iter++;
				}
				void* ptr = iter->first;
				ptr_map.erase(iter);
				hp->free(ptr);
			}
		}
		if (action % 7 == 0 && action % 2 != 0 && action % 3 != 0)
		{
			printf("Free all action\n");
			hp->free_all(tag);
			for (iter = ptr_map.begin(); iter != ptr_map.end(); )
			{
				if (iter->second == tag)
				{
					map<void*, int>::iterator tmp_iter = iter;
					iter++;
					ptr_map.erase(tmp_iter);
				} else {
					iter++;
				}
			}
		}
		if (action % 23 == 0 && action % 7 != 0 && action % 2 != 0 && action % 3 != 0)
		{
#ifdef PRIVATE_DEBUG
			hp->statistics();
#endif
		}
	}
	for (iter = ptr_map.begin(); iter != ptr_map.end(); iter++)
	{
		hp->free(iter->first);
	}
	printf("Time = %d ms\n", (clock() - start) * 1000 / CLOCKS_PER_SEC);
	return 0;
}

/**
 * execution of test above your class
 */

int main( int argc, char* argv[] )
{
	freopen("logfile.txt", "w", stdout);
	HANDLE threadlist[t_num];
	try
	{
		heap_ludmila hp_ludmila( 1024 * 1024 * 100, heap876::alloc_tagged );
		for (int i = 0; i < t_num; i++)
		{
			threadlist[i] = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)(test_general), &hp_ludmila, 0, 0);
		}
		WaitForMultipleObjects(t_num, threadlist, TRUE, INFINITE);
	} catch (exception e) {
		cout << e.what();
	}
	fclose(stdout);
}